﻿// Copyright Finbuckle LLC, Andrew White, and Contributors.
// Refer to the solution LICENSE file for more information.

using System.Net;
using System.Reflection;
using Finbuckle.MultiTenant.Abstractions;
using Finbuckle.MultiTenant.Stores.HttpRemoteStore;
using Moq;
using Newtonsoft.Json;
using Xunit;

namespace Finbuckle.MultiTenant.Test.Stores;

public class HttpRemoteStoreShould : MultiTenantStoreTestBase
{
    public class TestHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
                var result = new HttpResponseMessage();

                var numSegments = request.RequestUri!.Segments.Length;
                if (string.Equals(request.RequestUri.Segments[numSegments - 1], "initech", StringComparison.OrdinalIgnoreCase))
                {

                    var tenantInfo = new TenantInfo { Id = "initech-id", Identifier = "initech" };
                    var json = JsonConvert.SerializeObject(tenantInfo);
                    result.StatusCode = HttpStatusCode.OK;
                    result.Content = new StringContent(json);
                }
                else
                    result.StatusCode = HttpStatusCode.NotFound;

                return Task.FromResult(result);
            }
    }

    [Fact]
    public void ThrowIfTypedClientParamIsNull()
    {
            Assert.Throws<ArgumentNullException>(() => new HttpRemoteStore<TenantInfo>(null!, "http://example.com"));
        }

    [Theory]
    [InlineData("null")]
    [InlineData("")]
    [InlineData("invalidUri")]
    [InlineData("file://nothttp")]
    public void ThrowIfEndpointTemplateIsNotWellFormed(string uri)
    {
            var clientFactory = new Mock<IHttpClientFactory>();
            var client = new HttpRemoteStoreClient<TenantInfo>(clientFactory.Object);
            Assert.Throws<ArgumentException>(() => new HttpRemoteStore<TenantInfo>(client, uri));
        }

    [Fact]
    public void AppendTenantToTemplateIfMissing()
    {
            var clientFactory = new Mock<IHttpClientFactory>();
            var client = new HttpRemoteStoreClient<TenantInfo>(clientFactory.Object);
            var store = new HttpRemoteStore<TenantInfo>(client, "http://example.com/");

            var field = store.GetType().GetField("endpointTemplate", BindingFlags.NonPublic | BindingFlags.Instance);
            var endpointTemplate = field?.GetValue(store);

            Assert.Equal($"http://example.com/{HttpRemoteStore<TenantInfo>.DefaultEndpointTemplateIdentifierToken}", endpointTemplate);
        }

    [Fact]
    public void AppendTenantWithSlashToTemplateIfMissing()
    {
            var clientFactory = new Mock<IHttpClientFactory>();
            var client = new HttpRemoteStoreClient<TenantInfo>(clientFactory.Object);
            var store = new HttpRemoteStore<TenantInfo>(client, "http://example.com");

            var field = store.GetType().GetField("endpointTemplate", BindingFlags.NonPublic | BindingFlags.Instance);
            var endpointTemplate = field?.GetValue(store);

            Assert.Equal($"http://example.com/{HttpRemoteStore<TenantInfo>.DefaultEndpointTemplateIdentifierToken}", endpointTemplate);
        }

    // Basic store functionality tested in MultiTenantStoresShould.cs

    protected override IMultiTenantStore<TenantInfo> CreateTestStore()
    {
            var client = new HttpClient(new TestHandler());
            var clientFactory = new Mock<IHttpClientFactory>();
            clientFactory.Setup(f => f.CreateClient(It.IsAny<string>())).Returns(client);
            var typedClient = new HttpRemoteStoreClient<TenantInfo>(clientFactory.Object);
            return new HttpRemoteStore<TenantInfo>(typedClient, "http://example.com");
        }

    protected override IMultiTenantStore<TenantInfo> PopulateTestStore(IMultiTenantStore<TenantInfo> store)
    {
            throw new NotImplementedException();
        }

    // [Fact(Skip = "Not valid for this store.")]
    public override void GetTenantInfoFromStoreById()
    {
        }

    [Fact]
    public override void GetTenantInfoFromStoreByIdentifier()
    {
            base.GetTenantInfoFromStoreByIdentifier();
        }

    [Fact]
    public override void ReturnNullWhenGettingByIdentifierIfTenantInfoNotFound()
    {
            base.ReturnNullWhenGettingByIdentifierIfTenantInfoNotFound();
        }

    // [Fact(Skip = "Not valid for this store.")]
    public override void AddTenantInfoToStore()
    {
        }

    // [Fact(Skip = "Not valid for this store.")]
    public override void RemoveTenantInfoFromStore()
    {
        }

    // [Fact(Skip = "Not valid for this store.")]
    public override void UpdateTenantInfoInStore()
    {
        }
}